
package objserver;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import objserver.io.Receiver;
import objserver.io.Sender;
import objserver.serverlistener.ObjEvent;
import objserver.serverlistener.ObjEventListener;
import android.matrix.FileMatrix;
import android.matrix.MatrixStub;
import android.remotematrixclient.objclient.CommandWrap;

/**
 * La clase <code>CoDServer</code> se encarga de crear un servidor de objetos
 * para aplicaciones distribuidas. 
 *
 * @author Rafael Asprilla
 *
 */
public class CoDServer {

	/**
	 * Número de puerto TCP al que se va a enlazar el servidor. Normalmente es 
	 * el puerto 3000.
	 */
	private static int portnum;
	
	/**
	 * Servicio receptor de objetos.
	 */
	private static Receiver rcv;
	
	/**
	 * Servicio de envío de objetos.
	 */
	private static Sender snd;
	
	/**
	 * Función main
	 * @param args
	 */
	public static void main(String[] args) {
		
		if(args.length == 0){
			System.out.println("Usage: java TCPServer port_number");
			System.exit(-1);
		}
		portnum = Integer.parseInt(args[0]);
		
		try {
			Process prc = Runtime.getRuntime().exec("./clean", null, 
					new File("/home/drakoniss/tesis"));
			prc.waitFor();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("Iniciando CoDServer.");
		try {
			ServerSocket listener = new ServerSocket(portnum);
			for(;;){
				
				Socket server = listener.accept();
				System.out.println("Nueva conexión aceptada.");
				
				snd = new Sender(server);
				rcv = new Receiver(server);
				rcv.addListener(new ObjEventListener(){

					@Override
					public void handleClientEvent(ObjEvent evt) {
						process(evt);	
					}
					
				});
				new Thread(rcv).start();
			}
		} catch (IOException e) {
			System.err.println("Error al iniciar servidor");
			System.exit(-2);
		}
	}
	
	/**
	 * El método <code>process</code> se encarga de procesar todas las 
	 * solicitudes recibidas en la cola de entrada. 
	 * 
	 * @param evt
	 * Datos del evento que llama esta función.
	 */
	protected static synchronized void process(ObjEvent evt){
		CommandWrap response = null;
		if(evt.getSource() instanceof Receiver){
			Object data = null;
			CommandWrap cw = rcv.get();
			System.out.print("Command: "+cw.cmd+" received. ");
			System.out.println("ID: " + cw.id);
			if(cw.cmd.equals("PUT")){
				try {
					new FileMatrix((MatrixStub) cw.data);
				} catch (IOException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				}
				response = new CommandWrap(cw.cmd, data, true, true, cw.id);
			}
			if(cw.cmd.equals("GET")){
				MatrixStub ms = null;
				try {
					ms = new FileMatrix((String) cw.data).getStub();
				} catch (IOException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				}
				if(ms != null)
					response = new CommandWrap(cw.cmd, ms, true, true, cw.id);
				else
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
			}
			if(cw.cmd.equals("CPUS")){
				int cpus = 0;
				try {
					Process prc = Runtime.getRuntime().exec("/home/drakoniss/tesis/cpus");
					prc.waitFor();
					cpus = prc.exitValue();
				} catch (IOException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				} catch (InterruptedException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				}
				System.out.println("Total CPUs: " + cpus + " Available CPUs: " + (cpus - 1));
				data = Integer.valueOf(cpus);
				response = new CommandWrap(cw.cmd, data, true, true, cw.id);
			}
			if(cw.cmd.equals("EXE")){
				int result = 0;
				try {
					String cmd = "./split_stripes " + (String) cw.data;
					System.out.println(cmd);
					Process prc = Runtime.getRuntime().exec(cmd, null, new File("/home/drakoniss/tesis/"));
					prc.waitFor();
					result = prc.exitValue();
				} catch (IOException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				} catch (InterruptedException e) {
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				}
				if(result != 0)
					response = new CommandWrap(cw.cmd, null, true, false, cw.id);
				else
					response = new CommandWrap(cw.cmd, data, true, true, cw.id);
					
			}
			if(cw.cmd.equals("FIN")){
				rcv.close();
				snd.close();
				return;
			}
			snd.set(response);
			System.out.println("Command ACK: " +  response.cmd + ", ID: " + 
					response.id + ", Result: " + response.success);
			return;
		}
	}

}
